#include "WifiReFlash.h"

WifiReFlash::WifiReFlash()
{

}


/**
 * @brief 从Ntp服务器获取时间
 *
 */
bool WifiReFlash::getNtpTime()
{
    uint8_t maxRetry = 10;
    uint16_t parseResult;
    _udp.begin(this->_localPort);
    while (_udp.parsePacket() > 0)
        this->_udp.flush();
    // discard any previously received packets
    // Serial.println("Transmit NTP Request");
    // get a random server from the pool
    for (_ntpServerIndex = 0;
         _ntpServerIndex < (std::end(this->_ntpServerPool) - std::begin(this->_ntpServerPool));
         _ntpServerIndex++)
    {
#if DEBUG_EN
        Serial.printf("ntpServerName:%s\r\n",this->_ntpServerPool[_ntpServerIndex].c_str());
#endif
        _sendNTPpacket();

        for (maxRetry = 10;maxRetry > 0; --maxRetry)
        {
            parseResult = _udp.parsePacket();
            // if (_udp.parsePacket() >= NTP_PACKET_SIZE)
            if(parseResult > 0)
            {
#if DEBUG_EN
                Serial.println("Receive NTP Response");
#endif
                _udp.read(this->_packetBuffer, NTP_PACKET_SIZE); // read packet into the buffer
                unsigned long secsSince1900;
                // convert four bytes starting at location 40 to a long integer
                secsSince1900 = (unsigned long)this->_packetBuffer[40] << 24;
                secsSince1900 |= (unsigned long)this->_packetBuffer[41] << 16;
                secsSince1900 |= (unsigned long)this->_packetBuffer[42] << 8;
                secsSince1900 |= (unsigned long)this->_packetBuffer[43];
                this->ntpTime = (secsSince1900 - 2208988800UL + this->_timeZone * 3600);
                return true;
            }
            else
            {
#if DEBUG_EN
                Serial.println(parseResult);
#endif
                delay(100);
            }
        }
    }
#if DEBUG_EN
    Serial.println("No NTP Response :-(");
#endif
    this->ntpTime = 0;
    return false;
    // NTPClient ntpClient(_udp, this->_ntpServerPool[0].c_str(), 8*3600);
    // ntpClient.begin(_localPort);
    // ntpClient.update();
    // ntpTime = ntpClient.getEpochTime();
}


/**
 * @brief 从Ntp服务器获取时间
 *
 * @param localPort UDP端口
 */
bool WifiReFlash::getNtpTime(uint32_t localPort)
{
    // WiFiUDP Udp;
    this->_localPort = localPort;
    return this->getNtpTime();
}

/**
 * @brief 向NTP服务器发送请求
 *
 */
void WifiReFlash::_sendNTPpacket()
{
    // set all bytes in the buffer to 0
    memset(this->_packetBuffer, 0, NTP_PACKET_SIZE);
    // Initialize values needed to form NTP request
    // (see URL above for details on the packets)
    this->_packetBuffer[0] = 0b11100011; // LI, Version, Mode
    this->_packetBuffer[1] = 0;          // Stratum, or type of clock
    this->_packetBuffer[2] = 6;          // Polling Interval
    this->_packetBuffer[3] = 0xEC;       // Peer Clock Precision
    // 8 bytes of zero for Root Delay & Root Dispersion
    this->_packetBuffer[12] = 49;
    this->_packetBuffer[13] = 0x4E;
    this->_packetBuffer[14] = 49;
    this->_packetBuffer[15] = 52;
    // all NTP fields have been given values, now
    // you can send a packet requesting a timestamp:
    // _udp.beginPacket(this->_ntpServerIP, 123); // NTP requests are to port 123
    _udp.beginPacket(this->_ntpServerPool[_ntpServerIndex].c_str(), _localPort);
    _udp.write(this->_packetBuffer, NTP_PACKET_SIZE);
#if DEBUG_EN
    Serial.println("_sendNTPpacket()函数内packetBuffer:");
    for (uint8_t i = 0; i<NTP_PACKET_SIZE; ++i)
    {
        Serial.println(this->_packetBuffer[i]);
    }
#endif
    _udp.endPacket();
}

/**
 * @brief 根据ip获取 CityCode
 *
 * @return String CityCode
 */
String WifiReFlash::getCityCode()
{
    //配置请求地址。此处也可以不使用端口号和PATH而单纯的
    _httpClient.begin(this->_wificlient, "http://wgeo.weather.com.cn/ip/?_=" + String(now()));

    //设置请求头中的User-Agent
    _httpClient.setUserAgent(F("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"));
    _httpClient.addHeader("Referer", "http://www.weather.com.cn/");

    //如果服务器响应OK则从服务器获取响应体信息并通过串口输出
    uint32_t beginWait = millis();
    while (millis() - beginWait < 3000)
    {
        if (_httpClient.GET() == HTTP_CODE_OK)
        {
            String str = _httpClient.getString();
            uint16_t aa = str.indexOf("id=");
            if (aa > -1)
                return str.substring(aa + 4, aa + 4 + 9);
            else
                return "101010100";
        }
        else
            delay(10);
    }
    return "101010100";

    //关闭ESP8266与服务器连接
    _httpClient.end();
}

/**
 * @brief 获取城市天气
 *
 * @param cityCode 城市代码
 * @return uint8_t
 */
uint8_t WifiReFlash::getCityWeather(String cityCode, WeatherInfoStructure* weatherInfo)
{
    // WeatherInfoStructure weatherInfo;

    // String URL = "http://d1.weather.com.cn/dingzhi/" + cityCode + ".html?_="+String(now());//新
    // String URL = "http://d1.weather.com.cn/weather_index/" + _cityCode + ".html?_=" + String(now()); //原来

    _httpClient.begin(this->_wificlient, "http://d1.weather.com.cn/weather_index/" + cityCode + ".html?_=" + String(now())); //使用新方法

    //设置请求头中的User-Agent
    _httpClient.setUserAgent(F("Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1"));
    _httpClient.addHeader("Referer", "http://www.weather.com.cn/");

    //如果服务器响应OK则从服务器获取响应体信息并通过串口输出
    String str = "";
    uint32_t beginWait = millis();
    while (millis() - beginWait < 3000)
    {
        if (_httpClient.GET() == HTTP_CODE_OK)
        {
            str = _httpClient.getString();
#if DEBUG_EN
            Serial.println("获取天气成功");
#endif
            break;
        }
        else
            delay(10);
    }
    //关闭ESP8266与服务器连接
    _httpClient.end();
    if (str == "")
        return 1;

    /******************** 解析json [start]*************************/
    JsonDocument doc;

    /* 解析第一段JSON */
    String jsonString = str.substring(str.indexOf("weatherinfo\":") + 13, str.indexOf("};var alarmDZ"));
    deserializeJson(doc, jsonString);
    JsonObject jsonObject = doc.as<JsonObject>();
    // 今日天气
    weatherInfo->todayWeather = jsonObject["weather"].as<String>();
    // 今日天气代码
    weatherInfo->todayWeatherCode = (weatherTpye)atoi((jsonObject["weathercode"].as<String>()).substring(1, 4).c_str());

    /* 解析第二段JSON */
    jsonString = str.substring(str.indexOf("dataSK =") + 8, str.indexOf(";var dataZS"));
    deserializeJson(doc, jsonString);
    jsonObject = doc.as<JsonObject>();
    // 温度
    weatherInfo->temperature = jsonObject["temp"].as<int>();
    // 湿度
    String humidityStr = jsonObject["SD"].as<String>();
    if (humidityStr.length() == 3)
        weatherInfo->humidity = atoi(humidityStr.substring(0, 2).c_str());
    else
        weatherInfo->humidity = atoi(humidityStr.substring(0, 3).c_str());
    // 城市名称
    weatherInfo->cityName = jsonObject["cityname"].as<String>();
    // PM2.5空气指数
    weatherInfo->pm25Value = jsonObject["aqi_pm25"];
    // 实时天气代码
    weatherInfo->weatherCode = (weatherTpye)atoi((jsonObject["weathercode"].as<String>()).substring(1, 4).c_str());
    // 实时天气
    weatherInfo->weather = jsonObject["weather"].as<String>();
    // 风向
    weatherInfo->windDirection = jsonObject["WD"].as<String>();
    // 风速
    weatherInfo->windSpeed = jsonObject["WS"].as<String>();

    /* 解析第三段JSON */
    jsonString = str.substring(str.indexOf("\"f\":[") + 5, str.indexOf(",{\"fa"));
    deserializeJson(doc, jsonString);
    jsonObject = doc.as<JsonObject>();
    // 最低温度
    weatherInfo->minTemperature = jsonObject["fd"].as<int>();
    // 最高温度
    weatherInfo->maxTemperature = jsonObject["fc"].as<int>();

    /******************** 解析json [end]*************************/
    return 0;
}
